{-
.cpm 파일을 vtkImageData에서 로딩할 때 편한 형식의 파일로 변환한다.

* 대용량 파일 변환시 주의!
	Haskell IORef를 사용할 때 주의하지 않으면 메모리 누수가 발생한다.
	메모리 누수를 피하려면 IORef 변수 값을 화면에 찍어보면 된다(why?)
-}

import System
import System.IO
import System.IO.Unsafe
import Data.Maybe
import Control.Monad
import Control.Concurrent
import MyFFI
import Text.PrintScan as P -- install liboleg

-- import Data.ByteString.Char8 as B
-- import Text.Printf

varInt = unsafePerformIO . cIntNew

-- variables
x0 = varInt 10000
y0 = varInt 10000
z0 = varInt 10000
v0 = unsafePerformIO . cDoubleNew $ 10000
x1 = varInt (-10000)
y1 = varInt (-10000)
z1 = varInt (-10000)
v1 = unsafePerformIO . cDoubleNew $ (-10000)
vcnt = varInt 0

applyLine (a, b, c, d) = do
	minf x0 a
	minf y0 b
	minf z0 c
	cDoubleGet v0 >>= \t->cDoubleSet v0 (min t d)
	maxf x1 a
	maxf y1 b
	maxf z1 c
	cDoubleGet v1 >>= \t->cDoubleSet v1 (max t d)
	cIntGet vcnt >>= \t->cIntSet vcnt (t+1)
	where
		minf  var val = cIntGet var >>= \t->cIntSet var (min t val)
		maxf  var val = cIntGet var >>= \t->cIntSet var (max t val)

data CpmItem = CpmItem { x::Int,y::Int,z::Int,value::Double }
               deriving(Show,Read,Eq)

toLine cpmItem = mkLine "" [show (x cpmItem),show (y cpmItem),show (z cpmItem),show (value cpmItem)]

cpmJoin::(Int->Int->Int)->(Double->Double->Double)->CpmItem->CpmItem->CpmItem
cpmJoin binOp1 binOp2 t1 t2 = CpmItem{x=x', y=y', z=z', value=value'}
                      where
                           x' = binOp1 (x t1) (x t2)
                           y' = binOp1 (y t1) (y t2)
                           z' = binOp1 (z t1) (z t2)
                           value' = binOp2 (value t1) (value t2)

data CpmInfo = CpmInfo {
                count::Int,
                minValues::CpmItem,
                maxValues::CpmItem
                } deriving(Show,Read,Eq)

-- usage: mkLine "hi" ["1","2"] ==> "hi 1 2"
mkLine = foldl (\x y->x ++ " " ++ y)

-- this function is not perfect!
split :: String -> Char -> [String]
split [] delim = [""]
split (c:cs) delim
   | c == delim = "" : rest
   | otherwise = (c : head rest) : tail rest
   where
       rest = split cs delim

convertLine::String->Maybe (Int,Int,Int,Double)
convertLine cpmLine = f $ split cpmLine ' '
    where
        f [x,y,v,z] = Just (read x,read y,read z,read v)
        f _ = Nothing

-- uses sscanf of liboleg
convertLine'::String->Maybe (Int,Int,Int,Double)
convertLine' cpmLine = sscanf cpmLine (int P.^ int P.^ fmt(undefined::Double) P.^ int) (\a b c d->(a,b,d,c))

proc f = do
   end <- hIsEOF f
   when (not end) $ do
       ln <- hGetLine f
       let cpmItem = convertLine' ln
       when (cpmItem/=Nothing) $ do
          let item = (\(Just x)->x)  cpmItem
          applyLine item
	  c <- cIntGet vcnt
	  when (c `mod` 10000 == 0) $ do
			putStrLn $ "# progress " ++ show c
       proc f

--cpmFileConvert::FilePath->IO ()
cpmFileConvert cpmFile = do
     f <- openFile cpmFile ReadMode
     proc f 
     hClose f

check = do
	chk "split" $ split "1 2 11.1 3" ' ' == ["1","2","11.1","3"]
	chk "convertLine'" $ convertLine' "1 2 11.1 3" == Just (1,2,3,11.1)
	putStrLn "All OK."
	where
		chk name b = if b then putStrLn (name ++ " [OK]") else error (name ++ " Fail")

main = do
     args <- getArgs
     if args==[] then putStrLn "usage: cpm2img <cpm file>"
       else do
             let (cpmFile:_) = args
             let maxCnt = 0 -- read maxCnt0::Int
             -- h <- openFile (cpmFile ++ ".img") WriteMode
             let put = putStrLn
             put "# AUTO GENERATED BY cpm2img"
             put "# VERSION 1.0"
             put $ "# SOURCE FILE: " ++ cpmFile
             cpmFileConvert cpmFile
             cnt <- cIntGet vcnt
             put $ "COUNT " ++ show cnt
             put $ mkLine "MIN " [show' x0,show' y0,show' z0,show . unsafePerformIO . cDoubleGet $ v0]
             put $ mkLine "MAX " [show' x1,show' y1,show' z1,show . unsafePerformIO . cDoubleGet $ v1]
             put "CELLS"
             --readFile cpmFile >>= put
             --put "EOF"
             where
				show' t = show . unsafePerformIO . cIntGet $ t


